/**
 * Created by zhaocong on 2016/4/21.
 * 一些有用的JS
 */



// 泛函数
var Collie = function(str1) {
    this.add = function(str2) {
        return str1 + ' ' + str2;
    };
    return add;
};
console.log(Collie('Hello')('World')); // Hello World


/**
 * 操作session - localStorage
 */
$(window).on('load', function() {
    var loc = window.sessionStorage.key('loc');
    if (!loc) {
        setTimeout(function() {
            location.reload();
        }, 2000);
        sessionStorage.setItem('loc', 1);
    }
});


/**
 * 初始化底部footer
 */
window.onload = function() {
    if (document.body.scrollHeight > document.body.offsetHeight) {
        document.querySelector('footer').style.position = 'absolute';
    }
};


/**
 *  jQueryƽ回到顶部
 */
$(document).ready(function() {
    $("a.topLink").click(function() {
        $("html,body").animate({
            scrollTop: $($(this).attr("href")).offset().top + "px"
        }, {
            duration: 500,
            easing: "swing"
        });
        return false;
    });
});


/**
 * jQuery回到顶部 css
 */
$("#go-top").on("click", function() {
    pos = $(window).scrollTop();
    var body = $("body");
    body.css({ "margin-top": -pos + "px" });
    $(window).scrollTop(0);
    body.css("transition", "all .5s ease-in");
    body.css("margin-top", "0");
    body.on("webkitTransitionEnd transitionend msTransitionEnd oTransitionEnd", function() {
        body.css("transition", "none");
    });
});



/**
 * rem 改变页面大小 初始320
 * @type {Element}
 */
var docEl = document.documentElement,
    resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
    recalc = function() {
        docEl.style.fontSize = 20 * (docEl.clientWidth / 320) + 'px';
    };
window.addEventListener(resizeEvt, recalc, false);
document.addEventListener('DOMContentLoaded', recalc, false);



/**
 * fnc 斐波那契数列 ~
 * @param n
 * @returns {*}
 */
function fn(n) {
    if (n <= 2) {
        return 1;
    } else {
        return fn(n - 1) + fn(n - 2);
    }
}


/**
 * 禁止选择
 * @type {CSSStyleDeclaration}
 */
var bodyStyle = document.body.style;
bodyStyle.mozUserSelect = 'none';
bodyStyle.webkitUserSelect = 'none';


/**
 * 动态加载样式和JS
 * @type {{css: Function, js: Function}}
 */
var dynamicLoading = {
    css: function(path) {
        if (!path || path.length === 0) {
            throw new Error('argument "path" is required !');
        }
        var head = document.getElementsByTagName('head')[0];
        var link = document.createElement('link');
        link.href = path;
        link.rel = 'stylesheet';
        link.type = 'text/css';
        head.appendChild(link);
    },
    js: function(path) {
        if (!path || path.length === 0) {
            throw new Error('argument "path" is required !');
        }
        var head = document.getElementsByTagName('head')[0];
        var script = document.createElement('script');
        script.src = path;
        script.type = 'text/javascript';
        head.appendChild(script);
    }
};
//动态加载 CSS 文件
dynamicLoading.css("test.css");
//动态加载 JS 文件
dynamicLoading.js("test.js");


/**
 * 全屏显示代码
 * http://www.zhangxinxu.com/study/201210/html5-full-screen-api.html
 */
//进入全屏
function requestFullScreen() {
    var de = document.documentElement;
    if (de.requestFullscreen) {
        de.requestFullscreen();
    } else if (de.mozRequestFullScreen) {
        de.mozRequestFullScreen();
    } else if (de.webkitRequestFullScreen) {
        de.webkitRequestFullScreen();
    }
}
//退出全屏
function exitFullscreen() {
    var de = document;
    if (de.exitFullscreen) {
        de.exitFullscreen();
    } else if (de.mozCancelFullScreen) {
        de.mozCancelFullScreen();
    } else if (de.webkitCancelFullScreen) {
        de.webkitCancelFullScreen();
    }
}


/**
 * requestAnimationFrame 单帧动画
 */
(function() {
    var lastTime = 0;
    var vendors = ['webkit', 'moz'];
    for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
        window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
        window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] ||
            window[vendors[x] + 'CancelRequestAnimationFrame'];
    }
    if (!window.requestAnimationFrame) {
        window.requestAnimationFrame = function(callback, element) {
            var currTime = new Date().getTime();
            var timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
            var id = window.setTimeout(function() {
                callback(currTime + timeToCall);
            }, timeToCall);
            lastTime = currTime + timeToCall;
            return id;
        };
    }
    if (!window.cancelAnimationFrame) {
        window.cancelAnimationFrame = function(id) {
            clearTimeout(id);
        };
    }
}());


/**
 * 函数绑定
 * @param fn
 * @param context
 * @returns {Function}
 *
 * @example EventUtil.addHandler(btn, "click", bind(handler.handleClick, handler));
 * ES5 提供Bind方法 EventUtil.addHandler(btn, "click", handler.handleClick.bind(handler));
 */
function bind(fn, context) {
    return function() {
        return fn.apply(context, arguments);
    };
}

/**
 * 给手机设个密码
 * @param  {[type]} i =>            '680514237'[i] [description]
 * @return {[type]}   [description]
 */
//[4,7,6,5,2,8,7,3,2,0,1].map(i => '680514237'[i]).join('');


// 我们想得到选择年选择月有多少天的话，只需要
var temp = new Date("选择年/选择月+1/0");

// 或者
function is_leap(year) {
    return (year % 100 == 0 ? (year % 400 == 0 ? 1 : 0) : (year % 4 == 0 ? 1 : 0));
} //是否为闰年
var m_days = new Array(31, 28 + is_leap(ynow), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); //各月份的总天数


// 复制一个对象的方法
function clone3(obj) {
    function Clone() {}

    Clone.prototype = obj;
    var o = new Clone();
    for (var a in o) {
        if (typeof o[a] == "object") {
            o[a] = clone3(o[a]);
        }
    }
    return o;
}

// 检测dpi
// window.devicePixelRatio

// https://github.com/amfe/lib-flexible
// 你将永远无法写出1px宽度的东西，除此之外，inline的SVG等元素，也会按照逻辑像素来渲染，整个页面的清晰度会打折。
// 所以，手机淘宝用JS来动态写meta标签，代码类似这样：
var metaEl = doc.createElement('meta');
var scale = isRetina ? 0.5 : 1;
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
if (docEl.firstElementChild) {
    document.documentElement.firstElementChild.appendChild(metaEl);
} else {
    var wrap = doc.createElement('div');
    wrap.appendChild(metaEl);
    documen.write(wrap.innerHTML);
}


// 一个野生的压缩图种的方法 bat 文件
// copy /b 1.jpg+2.rar 3.jpg

// 判断浏览器类型
var browser = {
    versions: function() {
        var u = navigator.userAgent,
            app = navigator.appVersion;
        return {
            trident: u.indexOf('Trident') > -1, //IE内核
            presto: u.indexOf('Presto') > -1, //opera内核
            webKit: u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核
            gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐内核
            mobile: !!u.match(/AppleWebKit.*Mobile.*/), //是否为移动终端
            ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
            android: u.indexOf('Android') > -1 || u.indexOf('Adr') > -1, //android终端
            iPhone: u.indexOf('iPhone') > -1, //是否为iPhone或者QQHD浏览器
            iPad: u.indexOf('iPad') > -1, //是否iPad
            webApp: u.indexOf('Safari') == -1, //是否web应该程序，没有头部与底部
            weixin: u.indexOf('MicroMessenger') > -1, //是否微信 （2015-01-22新增）
            qq: u.match(/\sQQ/i) == " qq" //是否QQ
        };
    }(),
    language: (navigator.browserLanguage || navigator.language).toLowerCase()
};
//调用 browser.versions.mobile


// http://www.zhanxin.info/development/2013-05-17-html5-audio.html
// 音频事件
/*
 //类似 a 标签的 click、hover事件一样，audio 元素也有属于它的属性
 //定义一个事件测试函数，将打印出内容
 var eventTester = function(e){
 Media.addEventListener(e,function(){
 console.log((new Date()).getTime(),e);
 });
 }
 //下面列觉这些属性的含义
 eventTester("loadstart");   //客户端开始请求数据
 eventTester("progress");    //客户端正在请求数据
 eventTester("suspend");     //延迟下载
 eventTester("abort");       //客户端主动终止下载（不是因为错误引起），
 eventTester("error");       //请求数据时遇到错误
 eventTester("stalled");     //网速失速
 eventTester("play");        //play()和autoplay开始播放时触发
 eventTester("pause");       //pause()触发
 eventTester("loadedmetadata");  //成功获取资源长度
 eventTester("loadeddata");  //
 eventTester("waiting");     //等待数据，并非错误
 eventTester("playing");     //开始回放
 eventTester("canplay");     //可以播放，但中途可能因为加载而暂停
 eventTester("canplaythrough"); //可以播放，歌曲全部加载完毕
 eventTester("seeking");     //寻找中
 eventTester("seeked");      //寻找完毕
 eventTester("timeupdate");  //播放时间改变
 eventTester("ended");       //播放结束
 eventTester("ratechange");  //播放速率改变
 eventTester("durationchange");  //资源长度改变
 eventTester("volumechange");    //音量改变

 //错误状态
 Media.error; //null:正常
 Media.error.code; //1.用户终止 2.网络错误 3.解码错误 4.URL无效

 //网络状态
 Media.currentSrc; //返回当前资源的URL
 Media.src = value; //返回或设置当前资源的URL
 Media.canPlayType(type); //是否能播放某种格式的资源
 Media.networkState; //0.此元素未初始化  1.正常但没有使用网络  2.正在下载数据  3.没有找到资源
 Media.load(); //重新加载src指定的资源
 Media.buffered; //返回已缓冲区域，TimeRanges
 Media.preload; //none:不预载 metadata:预载资源信息 auto:

 //准备状态
 Media.readyState;    //1:HAVE_NOTHING 2:HAVE_METADATA 3.HAVE_CURRENT_DATA 4.HAVE_FUTURE_DATA 5.HAVE_ENOUGH_DATA
 Media.seeking; //是否正在seeking

 //回放状态
 Media.currentTime = value; //当前播放的位置，赋值可改变位置
 Media.startTime; //一般为0，如果为流媒体或者不从0开始的资源，则不为0
 Media.duration; //当前资源长度 流返回无限
 Media.paused; //是否暂停
 Media.defaultPlaybackRate = value;//默认的回放速度，可以设置
 Media.playbackRate = value;//当前播放速度，设置后马上改变
 Media.played; //返回已经播放的区域，TimeRanges，关于此对象见下文
 Media.seekable; //返回可以seek的区域 TimeRanges
 Media.ended; //是否结束
 Media.autoPlay;  //是否自动播放
 Media.loop;  //是否循环播放
 Media.play();    //播放
 Media.pause();   //暂停

 //控制
 Media.controls;//是否有默认控制条
 Media.volume = value; //音量
 Media.muted = value; //静音




 // 求圆上任意一点的位置

 圆点坐标：(x0,y0)
 半径：r
 角度：a0

 则圆上任一点为：（x1,y1）
 x1 = x0 + r * cos(a0 * 3.14 /180);
 y1 = y0 + r * sin(a0 * 3.14 /180);

 */

/**
 * 判断是不是手机
 */
(function() {
    var ua = window.navigator.userAgent,
        agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPod"],
        isPC = true;
    for (var i = 0, len = agents.length; i < len; i++) {
        if (ua.indexOf(agents[i]) > 0) {
            isPC = false;
            break;
        }
    }
    if (isPC == false) {
        window.location.href = './activity-BkZHfXUVx.html';
    }
})();


/**
 * 让两个图像反复循环
 * 绝对定位并在一条竖线上 y = top, this.height = 高度
 */
function cash(a, b) {
    a.y > this.height && (a.y = -this.height);
    b.y > this.height && (b.y = -this.height);
}


/**
 * 检测浏览器中是否存在此插件（在IE中无效）
 * @param 插件名 name
 * @return boolean 存在插件返回true，否则返回false
 * http://www.w2bc.com/Article/18682
 */
function hasPlugin(name) {
    name = name.toLowerCase();
    for (var i = 0; i < navigator.plugins.length; i++) {
        if (navigator.plugins[i].name.toLowerCase().indexOf(name) > -1) {
            return true;
        }
    }
    return false;
}

/**
 * 改变设备的dpr
 * @type {number}
 */
var scaleNum = 1 / window.devicePixelRatio;
var temp = '<meta name="viewport" content="width=device-width,initial-scale=' + scaleNum + ',minimum-scale=' + scaleNum + ',maximum-scale=' + scaleNum + ',user-scalable=no" />';
var oHead = document.getElementsByTagName('head')[0];
oHead.innerHTML += temp;


// 正则 RegExp
var date = '1991-12-11 ';
/\d+(-)\d+(-)\d+(\s)$/.test(date);
date.replace(RegExp.$1, '年').replace(RegExp.$2, '月').replace(RegExp.$3, '日');


// 设置页面后退缓存机制
// https://moyueating.github.io/2017/01/14/H5%E6%B5%8F%E8%A7%88%E5%99%A8%E5%92%8Cwebview%E5%90%8E%E9%80%80%E7%BC%93%E5%AD%98%E6%9C%BA%E5%88%B6/
// https://rockjins.github.io/2017/01/26/interviews-javascript/

// 函数防抖
// debounce函数用来包裹我们的事件
function debounce(fn, delay) {
    // 持久化一个timer
    let timer = null;
    // 闭包可以获取到timer
    return function() {
        // 通过函数获取到作用域和参数列表
        // 通过 'this' 和 'arguments'
        let context = this;
        let args = arguments;
        // 如果事件被触发，清除timer并重新开始计时
        clearTimeout(timer);
        timer = setTimeout(function() {
            fn.apply(context, args);
        }, delay);
    }
}
// 当用户滚动时函数会被调用
function foo() {
    console.log('You are scrolling!');
}
// 在事件触发的两秒后，我们包裹在debounce中的函数才会被触发
let elem = document.getElementById('container');
elem.addEventListener('scroll', debounce(foo, 2000));


// 移动开发的各种事情 ：http://mp.weixin.qq.com/s/JVUpsz9QHsNV0_7U-3HCMg
// http://www.jianshu.com/p/e95824e8fe13
// 不定期更新的Javascript技巧 https://rockjins.github.io/2017/02/06/javascript-skill/



// js获取样式
var bd = document.querySelector('body')
window.getComputedStyle(bd, null).getPropertyValue('background-color')

// js获取绝对位置
var d = document.querySelector('.like-group')
d.getBoundingClientRect()




// 将DOM生成canvas http://html2canvas.hertzen.com/documentation.html

// http://jekyll.com.cn/docs/sites/
// http://www.ruanyifeng.com/blog/2012/08/blogging_with_jekyll.html
// https://hexo.io/zh-cn/docs/


// canvas 状态
// https://www.w3cplus.com/canvas/canvas-states.html


// 项目命名
// https://juejin.im/post/58d0e5caa22b9d00643e8b51?utm_source=gold_browser_extension


// 弄点儿有用的 - 改造网站成 pwa
// https://juejin.im/post/58dba0b3a22b9d00647db6c3?utm_source=gold_browser_extension

// 基础问题，严格模式和非严格模式
// https://juejin.im/post/5905ccb8ac502e0063ebe0e2?utm_source=gold_browser_extension

// 日常的文件上传问题
// https://www.qcloud.com/community/article/985614?fromSource=gwzcw.114059.114059.114059

// 博客SEO
// https://juejin.im/post/590b451a0ce46300588c43a0?utm_source=gold_browser_extension

// English 前端单词儿本儿
// https://www.shanbay.com/wordbook/129934/

// 美丽的地球
// http://gallery.echartsjs.com/editor.html?c=xSk7XrQKpl


// 通过 chrome 调试 nodejs
// node --inspect --debug-brk target.js
// 最新版node不建议使用 --debug-brk 了，直接  node --inspect-brk
// 而且通过 chrome://inspect 可以很方便的查看监听的项目了，不需要自己手动复制 chrome-devtools 地址了，而且 inspect 这个命令起码是 6.6 就已经支持了
// https://nodejs.org/en/docs/inspector/


// 生成下载链接
// http://www.jb51.net/article/47723.htm

// H5视频直播
// https://mp.weixin.qq.com/s/MM5ZwCiWLAeHalsNYMImnw

// 前端导航
// http://www.alloyteam.com/nav/index.html

// 数据结构
// https://juejin.im/post/594dfe795188250d725a220a?utm_source=gold_browser_extension

// 文字过长怎么办
// http://svgtrick.com/tricks/06af9fabf7e2ecfad24856416b024968

// 删除不使用的css样式 简约到极致
// https://www.npmjs.com/package/purifycss
// https://github.com/purifycss/gulp-purifycss


// 移动端图片上传旋转、压缩的解决方案
// https://juejin.im/post/595599e75188250d99181801?utm_source=gold_browser_extension


// vsc 插件
// https://segmentfault.com/a/1190000006697219


// 滚动条样式
// https://www.lyblog.net/detail/314.html


// 文本域自动高度调整
// http://www.jacklmoore.com/autosize/


// 创建zip
// https://github.com/Stuk/jszip


// css loading
// http://www.cnblogs.com/lhb25/p/loading-spinners-animated-with-css3.html


// 科学上网
// https://ttt.tt/150/


// chrome 开发文档
// http://www.css88.com/doc/chrome-devtools/progressive-web-apps/


// react 中文API
// http://www.css88.com/react/docs/hello-world.html


// websocket 教程
// https://developer.mozilla.org/zh-TW/docs/WebSockets#Browser_compatibility
// https://socket.io/get-started/chat/


// 生成PDF
// https://github.com/linwalker/render-html-to-pdf
// https://github.com/omwteam/html2canvas
// http://mrrio.github.io/


// 贝塞尔曲线平滑计算公式
// http://blog.csdn.net/cdnight/article/details/48468945


// 用 d3 做变形动画
// https://laozhu.me/post/morphing-svg-icon-with-d3js/


// 动画时间轴
// https://juejin.im/entry/599cdae2f265da24782657a9?utm_source=gold_browser_extension



// 在所有DOM元素加载完成后添加元素
document.body.insertAdjacentHTML("BeforeEnd","<iframe></iframe>");


// 获取一个时间戳  ie10 以上
const t = window.performance.now();


// 傅里叶变换
// http://blog.jobbole.com/70549/


// cssnano 设置 http://cssnano.co/optimisations/
// cssnano({
//    zindex: false,
//    normalizeUrl: false,
//    normalizeUnicode: false,
//    minifyFontValues: false
// })



// iphone x 刘海解决方案
// 为了解决这个尴尬的情况，苹果公司给我们提供了一个设置 viewport 的 meta 标签的解决方案。
// viewport 可以设置的选项就是 viewport-fit, 它有三个可选值：
//
// contain: The viewport should fully contain the web content.
// 可视窗口完全包含网页内容cover: The web content should fully cover the viewport.
// 网页内容完全覆盖可视窗口auto: The default value, 同contain的作用


// DataURL与File,Blob,canvas对象之间的互相转换的Javascript
// http://blog.csdn.net/cuixiping/article/details/45932793



// 为什么(2.55).toFixed(1)等于2.5？
// https://juejin.im/post/5a11a9fef265da43284073b4?utm_source=gold_browser_extension
// 修正 浮点误差
if (!Number.prototype._toFixed) {
    Number.prototype._toFixed = Number.prototype.toFixed;
}

Number.prototype.toFixed = function(n) {
    return (this + 1e-14)._toFixed(n);
};



// 一些vue 轮子
// http://vue.shuxia123.com/#/


// canvas 拖拽效果
// http://www.tqtan.com/2016/03/27/drag-a-ball/



// 腾讯地图 API
// http://lbs.qq.com/tool/component-picker.html



// 当旋转图像变得模糊时
// backface-visibility: hidden;
// zoom: 101%;
// transform: rotate(90deg);



// canvas 叠加属性
// http://blog.csdn.net/laijieyao/article/details/41862473


// mac php 环境
// https://www.jianshu.com/p/f4fd87fea61c


// 请求跨域了咋整
// res.header('Access-Control-Allow-Origin', '*');

// 正则  gmi 全部 换行 大小写


// 防止 浏览器的自动记录滚动位置的功能
// window.history.scrollRestoration && (window.history.scrollRestoration = 'auto')


// headless chrome 模拟浏览器
// http://www.r9it.com/20171106/puppeteer.html


// 单枪匹马整个聊天室
// https://juejin.im/post/5b626a096fb9a04fdd7d7433?utm_source=gold_browser_extension


// css object-fit
// https://www.zhangxinxu.com/wordpress/2015/03/css3-object-position-object-fit/


// 音频示波器
// https://wavesurfer-js.org/examples/
// 一些介绍
// https://www.zhangxinxu.com/wordpress/2017/06/html5-web-audio-api-js-ux-voice/


// box shadow
// https://juejin.im/post/5be1023951882516fd36a38e?utm_source=gold_browser_extension


// 一些api 震动啥的
// https://juejin.im/post/5c92446b6fb9a070c022f0e2

// 动画的正常使用方式
// https://github.com/hustcc/canvas-nest.js/blob/master/src/CanvasNest.js

// 换肤功能
// https://www.zhangxinxu.com/wordpress/2019/02/link-rel-alternate-website-skin/

// canvas
// https://github.com/hustcc/canvas-nest.js/blob/master/src/CanvasNest.js

// FLIP 技术
// http://luchun.github.io/animating-layouts-with-the-flip-technique/


// 提交
// npx git-cz


// js 分片上传
// https://www.w3xue.com/exp/article/201812/11827.html
// https://github.com/shady-xia/Blog/tree/master/vue-simple-uploader


// 写个日历的参考
// https://github.com/mircode/calender/blob/master/js/calendar.js

function js_onload() {
  return document.createElement('script').readyState
  // @param {DOMElement} node
  // @param {!function()} callback asset.js makes sure callback is not NULL
  ? function(node, callback) {
    node.onreadystatechange = function() {
      var rs = node.readyState;
      if (rs === 'loaded' || rs === 'complete') {
        node.onreadystatechange = null;
        callback.call(this);
      }
    };
  }
  : function(node, callback) {
    node.addEventListener('load', callback, false);
  };
}

const node = document.createElement('script');
node.src = 'https://goss.cfp.cn/static/lib/three.min.js';
node.async = true;
document.head.appendChild(node);

this.js_onload()(node, () => {
  this.startPanorama();
});

// 无限滚动
// https://juejin.im/post/5de5baf2518825235b095cbe?utm_source=gold_browser_extension


// 图像处理
// https://github.com/chenshenhai/pictool


// OSS 直传
// https://help.aliyun.com/document_detail/91848.html?spm=a2c4g.11186623.2.16.16076e28yVcG40#concept-ynl-hky-2fb

// 切片上传
// https://juejin.im/post/5dff8a26e51d4558105420ed?utm_source=gold_browser_extension
// https://developer.mozilla.org/zh-CN/docs/Web/API/Blob/slice


// 生成 26 个字母
// latter: ['#', ...[...new Array(26)].map((_, i) => String.fromCharCode(65 + i))]


// 压缩 redis 数据
// https://www.danielauener.com/redis-with-node-js-gzip-mem-usage/


// js 媒体查询
const useMediaQuery = (query, whenTrue, whenFalse) => {
    if (typeof window === 'undefined' || typeof window.matchMedia === 'undefined') return whenFalse;

    const mediaQuery = window.matchMedia(query);
    const [match, setMatch] = React.useState(!!mediaQuery.matches);

    React.useEffect(() => {
        const handler = () => setMatch(!!mediaQuery.matches);
        mediaQuery.addEventListener('change', handler);
        return () => mediaQuery.removeEventListener('change', handler);
    }, []);

    return match ? whenTrue : whenFalse;
};


// 如何 在hook 中测量dom 尺寸
function MeasureExample() {
    const [rect, ref] = useClientRect();
    return (
      <>
        <h1 ref={ref}>Hello, world</h1>
        {rect !== null &&
          <h2>The above header is {Math.round(rect.height)}px tall</h2>
        }
      </>
    );
  }

function useClientRect() {
    const [rect, setRect] = useState(null);
    const ref = useCallback(node => {
        if (node !== null) {
            setRect(node.getBoundingClientRect());
        }
    }, []);
    return [rect, ref];
}
